# -*- coding: utf-8 -*-
'''
Wargame AI的任务、命令和细化方法
2020-04
'''
__author__ = 'Yu XH'

from myAI.asynchronous.infer_paras import *
# import myAI.asynchronous.RAE as alg
import myAI.asynchronous.paralize_RAE as alg
from myAI.const import *
import time
import copy

FAILURE = 'Failure'
SUCCESS = 'Success'


# =========================
# ======== 顶层任务 ========
# =========================

def output_firepower_method1(obj_id, fire_area, myAgent):
    """火力输出任务"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        move_shoot = True
    else:
        move_shoot = False
    # begin = time.time()
    fire_loc = infer_fire_loc(obj_id, fire_area, BopType.Vehicle, myAgent, move_shoot)  # 推理攻击点
    # print(
    #     f'-- infer_fire_loc time: {time.time() - begin:.3f}s fire loc：{fire_loc} obj_id: {obj_id} fire area: {fire_area}')
    if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
        alg.do_task('maneuver', obj_id, fire_loc, myAgent)  # 机动任务
    if shoot_ability(obj_id, myAgent):  # 保证行进间射击的连续性
        alg.do_task('fire_attack', obj_id, fire_area, myAgent)  # 进攻型射击任务
        alg.do_command(Success, obj_id, myAgent)  # 完成任务
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def defend_firepower_anti_control_methods1(obj_id, defend_target, directions, myAgent):
    """火力防御 - 反夺控"""
    if not directions:  # 方向为空时，判断为反夺控
        while myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank and shoot_check(obj_id, myAgent):
            alg.do_command(Fire, obj_id, myAgent)
        # begin = time.time()
        safe_loc = infer_safe_loc(myAgent.get_bop(obj_id), get_range(defend_target, 1, myAgent.get_map_size()),
                                  myAgent)  # 推理安全点
        # print(
        #     f'\t|- infer_safe_loc time: {time.time() - begin:.3f}s safe loc：{safe_loc} obj_id: {obj_id} defend target: {defend_target}')
        alg.do_task('maneuver', obj_id, safe_loc, myAgent)
        alg.do_task('guard2nd', obj_id, True, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def defend_firepower_common_method2(obj_id, defend_target, directions, myAgent):
    """火力防御 - 通用"""
    while myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank and shoot_check(obj_id, myAgent):
        alg.do_command(Fire, obj_id, myAgent)
    # begin = time.time()
    defend_loc = infer_defend_loc(myAgent.get_bop(obj_id), defend_target, directions, myAgent)  # 推理防守点
    # print(
    #     f'\t|- infer_defend_loc time: {time.time() - begin:.3f}s defend loc：{defend_loc} obj_id: {obj_id} defend target: {defend_target}')
    if myAgent.get_bop(obj_id)['cur_hex'] != defend_loc:
        alg.do_task('maneuver', obj_id, defend_loc, myAgent)  # 机动任务
    if shoot_ability(obj_id, myAgent):  # 保证行进间射击的连续性
        alg.do_task('fire_defend', obj_id, myAgent)  # 进攻型射击任务
    else:
        while True:
            if perceived_thread(obj_id, 60, myAgent):
                alg.do_task('hide', obj_id, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)


def support_firepower_guided_method1(obj_id, tar_area, myAgent):
    """火力支援 - 引导射击，目前只考虑战车的重型导弹"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.IFV:
        safty = 0.5
    else:
        safty = 0
    while True:
        # begin = time.time()
        supp_loc = infer_support_loc(obj_id, tar_area, myAgent)  # 推理火力支援点
        # print(
        #     f'-- infer_support_loc time: {time.time() - begin:.3f}s support loc：{supp_loc} obj_id: {obj_id} tar area: {tar_area}')
        if myAgent.get_bop(obj_id)['cur_hex'] != supp_loc:
            alg.do_task('rapid_march', obj_id, supp_loc, safty, myAgent)
        begin_step = copy.deepcopy(myAgent.observation['time']['cur_step'])
        while not perceived_thread(obj_id, 60, myAgent) and (myAgent.observation['time']['cur_step'] - begin_step < 75):  # 保证60秒内不会受伤害
            if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
            else:
                alg.do_command(Fire, obj_id, myAgent)
        if perceived_thread(obj_id, 60, myAgent):
            alg.do_task('hide', obj_id, myAgent)


def scout_mothod1(obj_id, scout_area, myAgent):
    """侦察"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.IFV:
        safty = 0.5
    else:
        safty = 0
    while True:
        # begin = time.time()
        scout_loc = infer_scout_loc(obj_id, scout_area, myAgent)
        # print(
        #     f'-- infer_scout_loc time: {time.time() - begin:.3f}s scout loc：{scout_loc} obj_id: {obj_id} scout area: {scout_area}')
        if myAgent.get_bop(obj_id)['cur_hex'] != scout_loc:
            alg.do_task('rapid_march', obj_id, scout_loc, safty, myAgent)
        begin_step = copy.deepcopy(myAgent.observation['time']['cur_step'])
        while not perceived_thread(obj_id, 40, myAgent) and myAgent.observation['time']['cur_step'] - begin_step < 75:  # 保证60秒内不会受伤害
            if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
            else:
                alg.do_command(Fire, obj_id, myAgent)
        if perceived_thread(obj_id, 40, myAgent):
            alg.do_task('hide', obj_id, myAgent)


def hide_common_method1(obj_id, myAgent):
    """躲避危险"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
        safty = 0
        hide_range = 1
    else:
        safty = 1
        hide_range = 5
    hide_loc = infer_safe_loc(myAgent.get_bop(obj_id), hide_range, myAgent)
    if myAgent.get_bop(obj_id)['cur_hex'] != hide_loc:
        alg.do_task('rapid_march', obj_id, hide_loc, safty, myAgent)


def hide2nd_common_method1(obj_id, myAgent):
    """躲避危险 - 用于round 5"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
        # 确定步兵的藏身区域
        candidate_locs = get_range(myAgent.get_bop(obj_id)['cur_hex'], 1, myAgent.get_map_size())
        hide_range, other_area = [], []
        for hex in candidate_locs:
            if hex == myAgent.get_bop(obj_id)['cur_hex']:
                continue
            flag_around_city = False
            for city in myAgent.observation['cities']:
                if cal_distance(hex, city['coord']) <= 1:
                    hide_range.append(hex)
                    flag_around_city = True
                    break
            if not flag_around_city:
                other_area.append(hex)
        if not hide_range:
            hide_range = other_area
        hide_loc = infer_safe_loc(myAgent.get_bop(obj_id), hide_range, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] != hide_loc:
            alg.do_task('maneuver', obj_id, hide_loc, myAgent)
    elif myAgent.get_bop(obj_id)['type'] == BopType.Aircraft:
        hide_range = 5
        hide_loc = infer_safe_loc(myAgent.get_bop(obj_id), hide_range, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] != hide_loc:
            alg.do_task('rapid_march', obj_id, hide_loc, 2, myAgent)
    else:
        hide_range = 3
        hide_loc = infer_safe_loc(myAgent.get_bop(obj_id), hide_range, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] != hide_loc:
            alg.do_task('maneuver', obj_id, hide_loc, myAgent)


def control_infantry_method1(obj_id, city_loc, myAgent):
    """夺控 - 步兵"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
        if myAgent.get_bop(obj_id)['cur_hex'] != city_loc:
            alg.do_task('maneuver', obj_id, city_loc, myAgent)
        while myAgent.get_city(city_loc)['flag'] != myAgent.color:
            if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                alg.do_command(Occupy, obj_id, myAgent)
            else:
                alg.do_command(Fire, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def control_common_method2(obj_id, city_loc, myAgent):
    """夺控 - 非步兵"""
    if myAgent.get_bop(obj_id)['cur_hex'] != city_loc:
        alg.do_task('maneuver', obj_id, city_loc, myAgent)
    while myAgent.get_city(city_loc)['flag'] != myAgent.color:
        if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
            alg.do_command(Occupy, obj_id, myAgent)
        else:
            alg.do_command(Fire, obj_id, myAgent)


def try_control_common_method1(obj_id, city_loc, myAgent):
    """尝试夺控"""
    if myAgent.get_bop(obj_id)['cur_hex'] != city_loc:
        alg.do_task('maneuver', obj_id, city_loc, myAgent)
    alg.do_command(Occupy, obj_id, myAgent)


def load_method1(ifv_id, inf_id, myAgent):
    """装载（步兵）"""
    while myAgent.get_bop(ifv_id)['cur_hex'] != myAgent.get_bop(inf_id)['cur_hex']:
        alg.do_task('maneuver', ifv_id, myAgent.get_bop(inf_id)['cur_hex'], myAgent)
    while myAgent.get_bop(inf_id)['on_board'] == 0:
        alg.do_command(GetOn, ifv_id, inf_id, myAgent)


def unload_method1(ifv_id, launching_id_list, safty, myAgent):
    """卸载"""
    launching_id_list = [launching_id_list] if isinstance(launching_id_list, int) else launching_id_list
    ucv_id_list = []
    cm_id_list = []
    man_id_list = []
    for launching_id in launching_id_list:
        if myAgent.get_bop(launching_id)['sub_type'] == BopType.UCV:
            ucv_id_list.append(launching_id)
        elif myAgent.get_bop(launching_id)['sub_type'] == BopType.CruiseMissile:
            cm_id_list.append(launching_id)
        elif myAgent.get_bop(launching_id)['sub_type'] == BopType.Man:
            man_id_list.append(launching_id)
    for launching_id in cm_id_list + ucv_id_list:  # 巡飞弹、无人战车下车
        while myAgent.get_bop(launching_id)['on_board']:  # 如果算子在车上
            if safty and perceived_thread(ifv_id, 0, myAgent):  # 如果当前在敌人的火力范围内，更换下车位置
                # begin = time.time()
                unload_loc = infer_safe_loc(myAgent.get_bop(ifv_id), 3, myAgent)  # 重新推理下车点
                # print(f'-- infer_unload_loc time: {time.time() - begin:.3f}s unload loc：{unload_loc} obj_id: {ifv_id}')
                while myAgent.get_bop(ifv_id)['cur_hex'] != unload_loc:
                    alg.do_command(Move, ifv_id, unload_loc, myAgent)
            else:
                alg.do_command(GetOff, ifv_id, launching_id, myAgent)
    for man_id in man_id_list:  # 步兵运输
        while myAgent.agenda.rae_task.get(man_id) and myAgent.get_bop(man_id)['on_board']:  # 有安排任务 且 如果步兵算子在车上
            if ifv_id not in myAgent.is_puppet:
                myAgent.is_puppet.append(ifv_id)  # 交由步兵算子控制战车
            alg.do_command(Pass, ifv_id, myAgent)
        while ifv_id in myAgent.is_puppet:
            myAgent.is_puppet.remove(ifv_id)  # 战车取回控制权


def deliver_method1(ifv_id, inf_id, tar_loc, myAgent):
    """2020-6-24 运输步兵到指定位置"""
    if myAgent.get_bop(inf_id)['on_board'] == 0:  # 步兵不在车上
        alg.do_task('load', ifv_id, inf_id, myAgent)  # 装载任务
    if myAgent.get_bop(ifv_id)['cur_hex'] != tar_loc:
        alg.do_task('rapid_march', ifv_id, tar_loc, 0.5, myAgent)  # 安全机动任务
    while myAgent.get_bop(inf_id)['get_off_remain_time'] <= 0:
        alg.do_command(GetOff, ifv_id, inf_id, myAgent)
    alg.do_command(Success, ifv_id, myAgent)  # 完成任务


def deliver_safe_method1(ifv_id, inf_id, tar_loc, myAgent):
    """（安全）运输步兵到指定位置"""
    if myAgent.get_bop(inf_id)['on_board'] == 0:  # 步兵不在车上
        alg.do_task('load', ifv_id, inf_id, myAgent)  # 装载任务
    if myAgent.get_bop(ifv_id)['cur_hex'] != tar_loc:
        alg.do_task('rapid_march', ifv_id, tar_loc, 0.5, myAgent)  # 安全机动任务
    while myAgent.get_bop(inf_id)['get_off_remain_time'] <= 0:
        if perceived_thread(ifv_id, 0, myAgent):  # 如果当前在敌人的火力范围内，更换下车位置
            unload_loc = infer_safe_loc(myAgent.get_bop(ifv_id), 3, myAgent)  # 重新推理下车点
            while myAgent.get_bop(ifv_id)['cur_hex'] != unload_loc:
                alg.do_command(Move, ifv_id, unload_loc, myAgent)
        else:
            alg.do_command(GetOff, ifv_id, inf_id, myAgent)
    alg.do_command(Success, ifv_id, myAgent)  # 完成任务


def cruise_missile_patrol_method1(obj_id, scout_area, myAgent):
    """巡飞弹巡逻任务"""
    while myAgent.agenda.get_bop(obj_id)['on_board'] == 1:
        alg.do_command(Pass, obj_id, myAgent)
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    # 接下来让巡飞弹在scout_area进行巡逻
    begin = time.time()
    patrol_path = infer_cm_path(myAgent.agenda.get_bop(obj_id)['cur_hex'], scout_area)  # 计算出巡飞弹的巡逻路线，巡逻路线是一个闭合环形
    print(
        f'-- infer_cm_path time: {time.time() - begin:.3f}s patrol path：{patrol_path} obj id: {obj_id} scout area: {scout_area}')
    if patrol_path:
        while myAgent.get_bop(obj_id)['cur_hex'] != patrol_path[0]:
            alg.do_command(Move, obj_id, patrol_path[0], myAgent)
        while True:
            if myAgent.agenda.get_bop(obj_id)['cur_hex'] == patrol_path[0]:
                alg.do_command(MovePath, obj_id, patrol_path[1:], myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def cruise_missile_method1(obj_id, myAgent):
    """2020-6-18 巡飞弹任务"""
    while myAgent.get_bop(obj_id)['on_board'] == 1:
        alg.do_command(Pass, obj_id, myAgent)
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    map_size = myAgent.get_map_size()
    n_hexes = map_size['row'] * map_size['col']
    while myAgent.get_bop(obj_id):  # 巡飞弹死亡，自动结束任务
        tar_id = get_cm_search_target(obj_id, myAgent.agenda.rae_situation.enemies, myAgent)  # 计算出巡飞弹的搜索对象
        # print(f'-- get_cm_search_target tar_id: {tar_id}')
        if not tar_id:
            search_loc = get_cm_random_search_loc(myAgent)
        else:  # 有需要搜索的敌方算子
            search_loc = matind_2_mapid(
                np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(tar_id)['pos_probs'])], map_size)
            # print(f'-- matind_2_mapid search_loc: {search_loc}')
        # move_path = myAgent.map.gen_move_route(myAgent.agenda.get_bop(obj_id)['cur_hex'], search_loc, 3)
        if myAgent.get_bop(obj_id)['cur_hex'] == search_loc:
            move_path = []
        else:
            move_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], search_loc)
        if len(move_path) > 5:
            move_path = move_path[:5]
        if not move_path:
            alg.do_command(Pass, obj_id, myAgent)
        while move_path:
            alg.do_command(Move, obj_id, move_path[0], myAgent)
            if myAgent.get_bop(obj_id)['cur_hex'] == move_path[0]:
                move_path.pop(0)
                cm_shoot_flag, shoot_id = cm_shoot_check(obj_id, myAgent)
                while cm_shoot_flag and myAgent.get_bop(obj_id) and myAgent.get_bop(
                        shoot_id):  # 巡飞弹射击
                    if shoot_id in myAgent.get_bop(obj_id)['see_enemy_bop_ids']:  # 如果目标算子在巡飞弹视野中
                        alg.do_command(FireTarget, obj_id, shoot_id, myAgent)
                    shoot_loc = matind_2_mapid(
                        np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(shoot_id)['pos_probs'])],
                        map_size)
                    shoot_path = myAgent.map.gen_move_route(myAgent.get_bop(obj_id)['cur_hex'], shoot_loc, 3)
                    if shoot_path:
                        next_loc = shoot_path[0]
                        while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                            alg.do_command(Move, obj_id, next_loc, myAgent)
                    else:
                        alg.do_command(Pass, obj_id, myAgent)
                    cm_shoot_flag, shoot_id = cm_shoot_check(obj_id, myAgent)


def cruise_missile_2nd_method1(obj_id, myAgent):
    """2020-7-6 巡飞弹任务（群队级想定）"""
    while myAgent.get_bop(obj_id)['on_board'] == 1:
        alg.do_command(Pass, obj_id, myAgent)
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    map_size = myAgent.get_map_size()
    n_hexes = map_size['row'] * map_size['col']
    while myAgent.get_bop(obj_id):  # 巡飞弹死亡，自动结束任务
        tar_id = get_cm_search_target_2nd(obj_id, myAgent.agenda.rae_situation.enemies, myAgent)  # 计算出巡飞弹的搜索对象
        if not tar_id:
            search_loc = get_cm_random_search_loc(myAgent)
        else:  # 有需要搜索的敌方算子
            search_loc = matind_2_mapid(
                np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(tar_id)['pos_probs'])], map_size)
            # move_path = myAgent.map.gen_move_route(myAgent.get_bop(obj_id)['cur_hex'], search_loc, 3)
        if myAgent.get_bop(obj_id)['cur_hex'] == search_loc:
            move_path = []
        else:
            move_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], search_loc)
        if len(move_path) > 5:
            move_path = move_path[:5]
        if not move_path:
            alg.do_command(Pass, obj_id, myAgent)
        else:
            while myAgent.get_bop(obj_id)['cur_hex'] != move_path[-1]:
                alg.do_command(MovePath, obj_id, move_path, myAgent)
        cm_shoot_flag, shoot_id = cm_shoot_check_2nd(obj_id, myAgent)
        while cm_shoot_flag and myAgent.get_bop(obj_id) and myAgent.get_bop(shoot_id):  # 巡飞弹射击
            if shoot_id in myAgent.get_bop(obj_id)['see_enemy_bop_ids']:  # 如果目标算子在巡飞弹视野中
                alg.do_command(FireTarget, obj_id, shoot_id, myAgent)
            shoot_loc = matind_2_mapid(
                np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(shoot_id)['pos_probs'])], map_size)
            shoot_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], shoot_loc)
            if shoot_path:
                while myAgent.get_bop(obj_id)['cur_hex'] != shoot_path[-1]:
                    alg.do_command(MovePath, obj_id, shoot_path, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
            cm_shoot_flag, shoot_id = cm_shoot_check_2nd(obj_id, myAgent)


def drone_scout_method1(obj_id, myAgent):
    """2020-7-21 无人机的侦察任务"""
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    map_size = myAgent.get_map_size()
    n_hexes = map_size['row'] * map_size['col']
    while myAgent.get_bop(obj_id):  # 无人机死亡，自动结束任务
        tar_id = get_drone_search_target(obj_id, myAgent.agenda.rae_situation.enemies, myAgent)  # 计算出无人机的搜索对象
        # print(f'-- get_cm_search_target tar_id: {tar_id}')
        if not tar_id:
            search_loc = get_cm_random_search_loc(myAgent)
        else:  # 有需要搜索的敌方算子
            search_loc = matind_2_mapid(
                np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(tar_id)['pos_probs'])], map_size)
            # print(f'-- matind_2_mapid search_loc: {search_loc}')
        # move_path = myAgent.map.gen_move_route(myAgent.agenda.get_bop(obj_id)['cur_hex'], search_loc, 3)
        if myAgent.get_bop(obj_id)['cur_hex'] == search_loc:
            move_path = []
        else:
            move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], search_loc, BopType.Drone, safty=1, myAgent=myAgent)
        if len(move_path) > 5:
            move_path = move_path[:5]
        if not move_path:
            alg.do_command(Pass, obj_id, myAgent)
        else:
            while myAgent.get_bop(obj_id)['cur_hex'] != move_path[-1]:
                alg.do_command(MovePath, obj_id, move_path, myAgent)


def ambush_tank_method1(obj_id, ambush_loc, myAgent):
    """伏击（该版本用于round 1, 3的想定）"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
            alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
        while True:
            if hit_check_any_enemy(obj_id, True, myAgent):
                alg.do_task('direct_shooting', obj_id, [], myAgent)
            if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
                alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def ambush_common_method2(obj_id, ambush_loc, myAgent):
    """伏击（该版本用于round 1, 3的想定）"""
    if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
        alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
    while not be_seen(obj_id, myAgent):  # 没有威胁
        alg.do_command(Pass, obj_id, myAgent)
    while be_seen(obj_id, myAgent):  # 被发现了，实施火力打击
        alg.do_task('direct_shooting', obj_id, [], myAgent)
    alg.do_command(Success, obj_id, myAgent)


def ambush2nd_infantry_method1(obj_id, ambush_loc, shelter_flag, myAgent):
    """伏击-步兵（该版本用于round 2, 3, 4的想定）
    :param shelter_flag: {bool} 是否实施掩蔽的判断
    """
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
        if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
            alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
        if shelter_flag:
            while True:
                if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                    alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
                else:
                    alg.do_command(Fire, obj_id, myAgent)
        else:
            while True:
                alg.do_command(Fire, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def ambush2nd_common_method2(obj_id, ambush_loc, shelter_flag, myAgent):
    """伏击（该版本用于round 2, 3, 4的想定）
    :param shelter_flag: {bool} 是否实施掩蔽的判断
    """
    if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
        alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
    if shelter_flag:
        if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
            alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
    while True:
        alg.do_command(Fire, obj_id, myAgent)


def ambush3rd_common_method1(obj_id, ambush_loc, shelter_flag, myAgent):
    """伏击（该版本用于round 3的想定）
    :param shelter_flag: {bool} 是否实施掩蔽的判断
    """
    if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
        alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
    if shelter_flag:
        while True:
            if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
            else:
                alg.do_command(Fire, obj_id, myAgent)
    else:
        while True:
            alg.do_command(Fire, obj_id, myAgent)


def ambush4th_tank_method1(obj_id, ambush_loc, shelter_flag, myAgent):
    """伏击（该版本用于round 4的想定）
    :param shelter_flag: {bool} 是否实施掩蔽的判断
    """
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
            alg.do_task('rapid_march', obj_id, ambush_loc, 0.5, myAgent)
        if shelter_flag:
            while True:
                if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
                    alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
                elif hit_check_any_enemy(obj_id, True, myAgent):
                    alg.do_task('direct_shooting', obj_id, [], myAgent)
                else:
                    alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
        else:
            while True:
                if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
                    alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
                elif hit_check_any_enemy(obj_id, True, myAgent):
                    alg.do_task('direct_shooting', obj_id, [], myAgent)
                else:
                    alg.do_command(Pass, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def ambush4th_common_method2(obj_id, ambush_loc, shelter_flag, myAgent):
    """伏击（该版本用于round 4的想定）
    :param shelter_flag: {bool} 是否实施掩蔽的判断
    """
    if myAgent.get_bop(obj_id) == BopType.Vehicle:
        safty = 0.5
    elif myAgent.get_bop(obj_id) == BopType.Aircraft:
        safty = 1
    else:
        safty = 0
    if myAgent.get_bop(obj_id)['cur_hex'] != ambush_loc:
        if safty == 0:
            alg.do_task('maneuver', obj_id, ambush_loc, myAgent)
        else:
            alg.do_task('rapid_march', obj_id, ambush_loc, safty, myAgent)
    if shelter_flag:
        while True:
            if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
            else:
                alg.do_task('direct_shooting', obj_id, [], myAgent)
    else:
        while True:
            alg.do_task('direct_shooting', obj_id, [], myAgent)


def air_defense_infantry_method1(obj_id, defend_loc, myAgent):
    if myAgent.get_bop(obj_id)['cur_hex'] != defend_loc:
        alg.do_task('rapid_march', obj_id, defend_loc, 0, myAgent)
    # while aircraft_in_shoot_range(obj_id, myAgent):
    while myAgent.get_bop(obj_id)['stop'] == 0 or myAgent.get_bop(obj_id)['weapon_cool_time'] > 0:
        alg.do_command(Pass, obj_id, myAgent)
    alg.do_task('direct_shooting', obj_id, [], myAgent)


def hunt_method1(obj_id, tar_id, myAgent):
    """追击（该版本用于round 1的想定）"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        move_shoot = True
    else:
        move_shoot = False
    if myAgent.agenda.get_enemy_info(tar_id):  # 敌人还没被击毙
        if not hit_check(obj_id, tar_id, move_shoot, myAgent):  # 不能有效击中敌人的判断
            fire_loc = infer_fire_loc(obj_id, myAgent.agenda.get_enemy_info(tar_id)['pos_probs'],
                                      myAgent.agenda.get_enemy(tar_id)['type'], myAgent, move_shoot)  # 推理攻击点
            if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
                alg.do_task('maneuver', obj_id, fire_loc, myAgent)  # 机动任务
            alg.do_task('hunt', obj_id, tar_id, myAgent)
        else:
            while hit_check(obj_id, tar_id, move_shoot, myAgent):
                alg.do_task('direct_shooting', obj_id, tar_id, myAgent)
            alg.do_task('hunt', obj_id, tar_id, myAgent)
    else:  # 敌人被击毙
        alg.do_command(Success, obj_id, myAgent)


def targeted_kill_cm_method1(obj_id, tar_id, myAgent):
    """定点清除（巡飞弹）"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.CruiseMissile:
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        map_size = myAgent.get_map_size()
        n_hexes = map_size['row'] * map_size['col']
        while myAgent.get_bop(obj_id):
            if tar_id in myAgent.get_bop(obj_id)['see_enemy_bop_ids']:  # 如果目标算子在巡飞弹视野中
                alg.do_command(FireTarget, obj_id, tar_id, myAgent)
            shoot_loc = matind_2_mapid(
                np.arange(n_hexes)[np.argmax(myAgent.agenda.get_enemy_info(tar_id)['pos_probs'])],
                map_size)
            move_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], shoot_loc)
            path = move_path[0:5] if len(move_path) >= 5 else move_path
            if path:
                while myAgent.get_bop(obj_id)['cur_hex'] != path[-1]:
                    alg.do_command(MovePath, obj_id, path, myAgent)
        else:
            alg.do_command(Success, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def targeted_kill_common_method2(obj_id, tar_id, myAgent):
    """定点清除（该版本用于round 2想定）"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        move_shoot = True
    else:
        move_shoot = False
    while myAgent.agenda.get_enemy_info(tar_id) and myAgent.get_bop(obj_id):
        fire_loc = infer_targeted_fire_loc(obj_id, tar_id, myAgent, move_shoot)  # 推理攻击点
        if not fire_loc:
            alg.do_command(Pass, obj_id, myAgent)
            break
        if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
            alg.do_task('maneuver', obj_id, fire_loc, myAgent)
        while hit_check(obj_id, tar_id, move_shoot, myAgent):
            alg.do_task('direct_shooting', obj_id, tar_id, myAgent)
    alg.do_command(Success, obj_id, myAgent)


def fire_propulsion_aircraft_method1(obj_id, myAgent):
    """火力推进任务 - 空中算子"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Aircraft:
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        while True:
            # begin = time.time()
            fire_loc = infer_fire_propulsion_loc(obj_id, myAgent)
            # print(f'\t|- infer_fire_propulsion_loc time: {time.time() - begin:.3f}s fire loc：{fire_loc} obj_id: {obj_id}')
            if (not fire_loc) or (not shoot_ability(obj_id, myAgent)):  # 没有打击目标，躲起来
                safe_loc = infer_safe_loc(myAgent.get_bop(obj_id), 20, myAgent)
                if myAgent.get_bop(obj_id)['cur_hex'] != safe_loc:
                    move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], safe_loc,
                                               myAgent.get_bop(obj_id)['sub_type'], safty=1, myAgent=myAgent)
                    step_len, max_step, min_step = 6, 10, 5
                    length = min(len(move_path) // step_len + min_step, max_step)
                    next_path = list(move_path[0:length]) if len(move_path) >= length else list(move_path)
                    if next_path:
                        while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                            alg.do_command(MovePath, obj_id, next_path, myAgent)
                else:
                    alg.do_command(Pass, obj_id, myAgent)
                continue
            if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
                move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], fire_loc,
                                           myAgent.get_bop(obj_id)['sub_type'], safty=1, myAgent=myAgent)
                step_len, max_step, min_step = 6, 10, 5
                length = min(len(move_path) // step_len + min_step, max_step)
                next_path = list(move_path[0:length]) if len(move_path) >= length else list(move_path)
                if next_path:
                    while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                        alg.do_command(MovePath, obj_id, next_path, myAgent)
            if myAgent.get_bop(obj_id)['cur_hex'] == fire_loc:
                while hit_check_any_enemy(obj_id, False, myAgent):
                    alg.do_task('direct_shooting', obj_id, [], myAgent)
                    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Helicopter:
                        enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.LargeAircraft]
                    else:
                        enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.LittleAircraft]
                    cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                    # print(f"\t|= 直升机{obj_id}的当前威胁：{enemy_threat[cur_loc_ind]}")
                    if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，重新找进攻点
                        break
                else:
                    alg.do_command(Pass, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def fire_propulsion_common_method2(obj_id, myAgent):
    """火力推进任务"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        move_shoot = True
    else:
        move_shoot = False
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    while True:
        # begin = time.time()
        fire_loc = infer_fire_propulsion_loc(obj_id, myAgent)
        # print(f'\t|- infer_fire_propulsion_loc time: {time.time() - begin:.3f}s fire loc：{fire_loc} obj_id: {obj_id}')
        if not fire_loc:
            break
        if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
            if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
                safty = 0.2
            else:
                safty = 0.5
            move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], fire_loc, myAgent.get_bop(obj_id)['type'],
                                       safty, myAgent)
            step_len, max_step, min_step = 3, 4, 2
            length = min(len(move_path) // step_len + min_step, max_step)
            next_path = move_path[0:length] if len(move_path) >= length else move_path
            while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                if myAgent.get_bop(obj_id)['stop'] == 0 and shoot_check(obj_id, myAgent) and \
                        myAgent.get_bop(obj_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                    alg.do_command(Fire, obj_id, myAgent)
                elif occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                else:
                    alg.do_command(MovePath, obj_id, next_path, myAgent)
            if myAgent.get_city(next_path[-1]):  # 机动中可夺控M
                while occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] == fire_loc:
            while hit_check_any_enemy(obj_id, move_shoot, myAgent):
                alg.do_task('direct_shooting', obj_id, [], myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
    alg.do_command(Success, obj_id, myAgent)


def assult_common_method1(obj_id, enemy_ids, myAgent):
    """袭击推进任务"""
    if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
        move_shoot = True
    else:
        move_shoot = False
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    while True:
        # begin = time.time()
        fire_loc = infer_assult_loc(obj_id, enemy_ids, myAgent)
        # print(f'\t|- infer_fire_propulsion_loc time: {time.time() - begin:.3f}s fire loc：{fire_loc} obj_id: {obj_id}')
        if not fire_loc:
            break
        if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
            if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
                safty = 0.2
            else:
                safty = 0.5
            move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], fire_loc, myAgent.get_bop(obj_id)['type'],
                                       safty, myAgent)
            step_len, max_step, min_step = 3, 4, 2
            length = min(len(move_path) // step_len + min_step, max_step)
            next_path = move_path[0:length] if len(move_path) >= length else move_path
            while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                if myAgent.get_bop(obj_id)['stop'] == 0 and shoot_check(obj_id, myAgent) and \
                        myAgent.get_bop(obj_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                    alg.do_command(Fire, obj_id, myAgent)
                elif occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                else:
                    alg.do_command(MovePath, obj_id, next_path, myAgent)
            if myAgent.get_city(next_path[-1]):  # 机动中可夺控M
                while occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] == fire_loc:
            while hit_check_any_enemy(obj_id, move_shoot, myAgent):
                alg.do_task('direct_shooting', obj_id, [], myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
    alg.do_command(Success, obj_id, myAgent)


def search_clean_tank_method1(tk_id, tar_loc, myAgent):
    """坦克机动到tar_loc，沿途清空敌方算子"""
    while myAgent.get_bop(tk_id)['cur_hex'] != tar_loc:
        move_path = myAgent.map.gen_move_route(myAgent.get_bop(tk_id)['cur_hex'], tar_loc, get_mod(tk_id, myAgent))
        if move_path:
            alg.do_task('maneuver', tk_id, move_path[0], myAgent)
        while hit_check_any_enemy(tk_id, True, myAgent):
            alg.do_task('direct_shooting', tk_id, [], myAgent)
    alg.do_command(Success, tk_id, myAgent)


def guide_fire_method1(obj_id, myAgent):
    """引导射击火力输出任务"""
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    while True:
        # begin = time.time()
        fire_loc = infer_guide_fire_loc(obj_id, myAgent)
        # print(
        #     f'-- infer_guide_fire_loc time: {time.time() - begin:.3f}s fire loc：{fire_loc} obj_id: {obj_id}')
        if not fire_loc:
            if myAgent.get_bop(obj_id)['type'] != BopType.Aircraft:
                alg.do_command(Pass, obj_id, myAgent)
            else:
                safe_loc = infer_safe_loc(myAgent.get_bop(obj_id), 5, myAgent)
                if myAgent.get_bop(obj_id)['cur_hex'] != safe_loc:
                    move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], safe_loc,
                                               myAgent.get_bop(obj_id)['sub_type'], safty=2, myAgent=myAgent)
                    if move_path:
                        while myAgent.get_bop(obj_id)['cur_hex'] != move_path[-1]:
                            alg.do_command(MovePath, obj_id, move_path, myAgent)
                else:
                    alg.do_command(Pass, obj_id, myAgent)
            continue
        if myAgent.get_bop(obj_id)['cur_hex'] != fire_loc:
            if myAgent.get_bop(obj_id)['type'] != BopType.Aircraft:
                move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], fire_loc, myAgent.get_bop(obj_id)['type'],
                                           safty=0.5, myAgent=myAgent)
                next_path = move_path[:4] if len(move_path) >= 4 else move_path
                while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                    alg.do_command(MovePath, obj_id, next_path, myAgent)
            else:  # 空中算子的最小机动粒度是5格
                move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], fire_loc,
                                           myAgent.get_bop(obj_id)['sub_type'], safty=2, myAgent=myAgent)
                next_path = move_path[:5] if len(move_path) > 5 else move_path
                while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                    alg.do_command(MovePath, obj_id, next_path, myAgent)
        if myAgent.get_bop(obj_id)['cur_hex'] == fire_loc:
            while vehicle_in_sight_check(obj_id, myAgent) and guide_ability(obj_id, myAgent):
                alg.do_task('direct_shooting', obj_id, [], myAgent)
                if myAgent.get_bop(obj_id)['sub_type'] == BopType.Drone:
                    enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.LittleAircraft]
                    cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                    if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，重新找引导点
                        break
            else:
                alg.do_command(Pass, obj_id, myAgent)


def jm_salvo_method1(arti_id, tar_loc, myAgent):
    """间瞄齐射任务"""
    while not jm_salvo_check(arti_id, tar_loc, myAgent):
        alg.do_command(JMShoot, arti_id, tar_loc, myAgent)
    while jm_salvo_check(arti_id, tar_loc, myAgent):
        alg.do_command(Pass, arti_id, myAgent)
    alg.do_command(Success, arti_id, myAgent)


def direct_artilleries_method1(obj_id, tar_loc, myAgent):
    """炮兵校射任务"""
    end_step = myAgent.observation['time']['cur_step'] + 150
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    directing_loc = None
    while end_step - myAgent.observation['time']['cur_step'] > 0:
        directing_loc = infer_directing_loc(obj_id, tar_loc,
                                            end_step - myAgent.observation['time']['cur_step'],
                                            myAgent)  # 推理校射格
        if not directing_loc:
            break
        elif myAgent.get_bop(obj_id)['cur_hex'] == directing_loc:
            alg.do_task('guard2nd', obj_id, False, myAgent)
        else:
            if myAgent.get_bop(obj_id)['type'] == BopType.Aircraft:
                alg.do_task('rapid_march', obj_id, directing_loc, 2, myAgent)
            elif myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
                alg.do_task('maneuver', obj_id, directing_loc)
            else:
                alg.do_task('rapid_march', obj_id, directing_loc, 0.5, myAgent)
    if directing_loc:
        alg.do_command(Success, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def infantry_tank_coordination_method1(tk_id, inf_id, myAgent):
    """步坦协同任务"""
    while True:
        enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.Vehicle]
        cur_loc_ind = mapid_2_matind(myAgent.get_bop(tk_id)['cur_hex'], myAgent.get_map_size())
        if enemy_threat[cur_loc_ind] > 7:  # 威胁过大时，躲避
            alg.do_task('hide2nd', tk_id, myAgent)
        elif myAgent.get_bop(tk_id)['cur_hex'] != myAgent.get_bop(inf_id)['cur_hex']:
            alg.do_task('maneuver', tk_id, myAgent.get_bop(inf_id)['cur_hex'], myAgent)
        else:
            alg.do_command(Pass, tk_id, myAgent)


# =========================
# ======== 普通任务 ========
# =========================


def maneuver_aircraft_method1(obj_id, move_loc, myAgent):
    """空中算子机动"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Aircraft:  # 空中算子
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
            # move_path = myAgent.map.gen_move_route(myAgent.agenda.get_bop(obj_id)['cur_hex'], move_loc, MoveType.Walk)  # 步兵的机动路线规划需要修改，加上格数的属性
            move_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], move_loc)
            if len(move_path) > 5:
                move_path = move_path[:5]
            while myAgent.get_bop(obj_id)['cur_hex'] != move_path[-1]:
                alg.do_command(MovePath, obj_id, move_path, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def maneuver_path_infantry_method2(obj_id, path, myAgent):
    """步兵机动（路线）"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry and isinstance(path, list):  # 步兵算子
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        move_path = list(path)
        while move_path:
            len_path = len(move_path)
            next_loc = move_path.pop(0)
            if len_path >= 3:  # 如果当前距离目标3格以上
                while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                    alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
            elif len_path == 2:  # 如果当前距离目标2格
                while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                    alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
            elif len_path <= 1:  # 如果当前距离目标1格以下
                if myAgent.get_bop(obj_id)['tire'] == 0:  # 不疲劳
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
                else:
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
            while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                else:
                    alg.do_command(MovePath, obj_id, [next_loc], myAgent)
            if myAgent.get_city(next_loc):  # 机动中可夺控
                if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def maneuver_infantry_method3(obj_id, move_loc, myAgent):
    """步兵机动"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry and isinstance(move_loc, int):  # 步兵算子
        while myAgent.get_bop(obj_id)['on_board'] or myAgent.get_bop(obj_id)['get_on_remain_time'] > 0:  # 如果步兵算子opr在车上，先根据目的地运输步兵
            if myAgent.get_bop(obj_id)['car'] in myAgent.is_puppet:
                alg.do_task('transport', myAgent.get_bop(obj_id)['car'], obj_id, move_loc, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
            # move_path = myAgent.map.gen_move_route(myAgent.agenda.get_bop(obj_id)['cur_hex'], move_loc, MoveType.Walk)  # 步兵的机动路线规划需要修改，加上格数的属性
            move_path = gen_infantry_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc, myAgent)
            if move_path:
                next_loc = move_path[0]
                len_path = len(move_path)
                if len_path >= 3:  # 如果当前距离目标3格以上
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
                elif len_path == 2:  # 如果当前距离目标2格
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
                elif len_path <= 1:  # 如果当前距离目标1格以下
                    if myAgent.get_bop(obj_id)['tire'] == 0:  # 不疲劳
                        while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                            alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
                    else:
                        while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                            alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
                while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                    if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                        alg.do_command(Occupy, obj_id, myAgent)
                    else:
                        alg.do_command(MovePath, obj_id, [next_loc], myAgent)
                if myAgent.get_city(next_loc):  # 机动中可夺控
                    if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                        alg.do_command(Occupy, obj_id, myAgent)
            else:
                if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                elif (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                    alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
                else:
                    alg.do_task('direct_shooting', obj_id, [], myAgent)
                artillery_threat = myAgent.agenda.rae_situation.artillery_threat
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if artillery_threat[cur_loc_ind] >= 3:  # 有3门炮同时到达本格，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def maneuver_path_common_method4(obj_id, path, myAgent):
    """普通机动（路线）"""
    if isinstance(path, list):  # 路径任务
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        move_path = path
        while move_path:
            if len(move_path) >= 3:
                next_path = list(move_path[:3])
                del move_path[:3]
            else:
                next_path = list(move_path)
                move_path.clear()
            while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                if myAgent.get_bop(obj_id)['stop'] == 0 and shoot_check(obj_id, myAgent) and \
                        myAgent.get_bop(obj_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                    alg.do_command(Fire, obj_id, myAgent)
                elif occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                else:
                    alg.do_command(MovePath, obj_id, next_path, myAgent)
            if myAgent.get_city(next_path[-1]):  # 机动中可夺控
                if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)  # 失败命令


def maneuver_common_method5(obj_id, move_loc, myAgent):
    """普通机动"""
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    move_path = myAgent.map.gen_move_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc, get_mod(obj_id, myAgent))
    while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
        if len(move_path) >= 3:
            next_path = list(move_path[:3])
            del move_path[:3]
        else:
            next_path = list(move_path)
            move_path.clear()
        while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
            if myAgent.get_bop(obj_id)['stop'] == 0 and shoot_check(obj_id, myAgent) and \
                    myAgent.get_bop(obj_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                alg.do_command(Fire, obj_id, myAgent)
            elif occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                alg.do_command(Occupy, obj_id, myAgent)
            else:
                alg.do_command(MovePath, obj_id, next_path, myAgent)
        if myAgent.get_city(next_path[-1]):  # 机动中可夺控
            if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                alg.do_command(Occupy, obj_id, myAgent)


def rapid_march_aircraft_method1(obj_id, move_loc, safty, myAgent):
    """快速机动 - 空中算子"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Aircraft:
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
            if safty == 0:
                move_path = get_line(myAgent.get_bop(obj_id)['cur_hex'], move_loc)
            else:
                move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc,
                                           myAgent.get_bop(obj_id)['sub_type'], safty, myAgent)
            step_len, max_step, min_step = 6, 10, 5
            length = min(len(move_path) // step_len + min_step, max_step)
            next_path = move_path[0:length] if len(move_path) >= length else move_path
            while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
                alg.do_command(MovePath, obj_id, next_path, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def rapid_march_infantry_method2(obj_id, move_loc, safty, myAgent):
    """快速机动 - 步兵"""
    if myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
        while myAgent.get_bop(obj_id)['move_path']:
            alg.do_command(Pass, obj_id, myAgent)
        while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
            # move_path = myAgent.map.gen_move_route(myAgent.agenda.get_bop(obj_id)['cur_hex'], move_loc, MoveType.Walk)  # 步兵的机动路线规划需要修改，加上格数的属性
            move_path = gen_infantry_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc, myAgent)
            if move_path:
                next_loc = move_path[0]
                len_path = len(move_path)
                if len_path >= 3:  # 如果当前距离目标3格以上
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
                elif len_path == 2:  # 如果当前距离目标2格
                    while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                        alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
                elif len_path <= 1:  # 如果当前距离目标1格以下
                    if myAgent.get_bop(obj_id)['tire'] == 0:  # 不疲劳
                        while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel2:
                            alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel2, myAgent)  # 二级冲锋
                    else:
                        while myAgent.get_bop(obj_id)['move_state'] != MoveState.ChargeLevel1:
                            alg.do_command(ChangeState, obj_id, MoveState.ChargeLevel1, myAgent)  # 一级冲锋
                while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                    if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                        alg.do_command(Occupy, obj_id, myAgent)
                    else:
                        alg.do_command(MovePath, obj_id, [next_loc], myAgent)
                if myAgent.get_city(next_loc):  # 机动中可夺控
                    if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                        alg.do_command(Occupy, obj_id, myAgent)
            else:
                if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                    alg.do_command(Occupy, obj_id, myAgent)
                elif (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                    alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
                else:
                    alg.do_task('direct_shooting', obj_id, [], myAgent)
                artillery_threat = myAgent.agenda.rae_situation.artillery_threat
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if artillery_threat[cur_loc_ind] >= 3:  # 有3门炮同时到达本格，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def rapid_march_common_method3(obj_id, move_loc, safty, myAgent):
    """快速机动"""
    while myAgent.get_bop(obj_id)['move_path']:
        alg.do_command(Pass, obj_id, myAgent)
    while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
        if safty == 0:
            move_path = myAgent.map.gen_move_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc,
                                                   get_mod(obj_id, myAgent))
        else:
            move_path = gen_safe_route(myAgent.get_bop(obj_id)['cur_hex'], move_loc,
                                       myAgent.get_bop(obj_id)['type'], safty, myAgent)
        step_len, max_step, min_step = 3, 4, 2
        length = min(len(move_path) // step_len + min_step, max_step)
        next_path = move_path[0:length] if len(move_path) >= length else move_path
        while myAgent.get_bop(obj_id)['cur_hex'] != next_path[-1]:
            if myAgent.get_bop(obj_id)['stop'] == 0 and shoot_check(obj_id, myAgent) and \
                    myAgent.get_bop(obj_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                alg.do_command(Fire, obj_id, myAgent)
            elif occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                alg.do_command(Occupy, obj_id, myAgent)
            else:
                alg.do_command(MovePath, obj_id, next_path, myAgent)
        if myAgent.get_city(next_path[-1]):  # 机动中可夺控M
            while occupy_check(myAgent.get_bop(obj_id), myAgent.observation):
                alg.do_command(Occupy, obj_id, myAgent)


# def march_organized_method2(obj_id, move_loc, myAgent):
#     """进军-有组织机动"""
#     if is_moving(myAgent.get_bop(obj_id)):  # 处于机动中
#         if force_stop_check(obj_id, move_loc, myAgent):  # 强制停止的判断
#             while is_moving(myAgent.get_bop(obj_id)):
#                 alg.do_command(StopMove, obj_id, myAgent)
#     while myAgent.get_bop(obj_id)['cur_hex'] != move_loc:
#         if not rapid_march_check(myAgent.get_bop(obj_id), move_loc):  # 快速机动条件判断
#             if perceived_thread(obj_id, myAgent):
#                 while is_moving(myAgent.get_bop(obj_id)):  # 处于机动中
#                     alg.do_command(StopMove, obj_id, myAgent)
#                 alg.do_task('guard', obj_id, myAgent)
#         alg.do_command(Move, obj_id, move_loc, myAgent)


# def transport_method1(ifv_id, inf_id, tar_loc, myAgent):
#     """运输步兵"""
#     begin = time.time()
#     off_loc = infer_off_loc(ifv_id, tar_loc, myAgent)  # 根据步兵的目标点推理下车点
#     print(f'-- infer_off_loc time: {time.time() - begin:.3f}s off loc：{off_loc} obj_id: {ifv_id} tar loc: {tar_loc}')
#     if myAgent.agenda.get_bop(ifv_id)['cur_hex'] != off_loc:
#         alg.do_task('maneuver', ifv_id, off_loc, myAgent)
#     if myAgent.agenda.get_bop(ifv_id)['cur_hex'] == off_loc:
#         while myAgent.agenda.get_bop(inf_id)['on_board']:  # 如果步兵算子opr在车上
#             if in_enemies_range(ifv_id, myAgent):  # 如果当前在敌人的火力范围内，更换下车位置
#                 begin = time.time()
#                 off_loc = infer_off_loc(ifv_id, tar_loc, myAgent)  # 重新推理下车点
#                 print(
#                     f'-- infer_off_loc time: {time.time() - begin:.3f}s reoff loc：{off_loc} obj_id: {ifv_id} tar loc: {tar_loc}')
#                 if myAgent.agenda.get_bop(ifv_id)['cur_hex'] != off_loc:
#                     alg.do_task('maneuver', ifv_id, off_loc, myAgent)
#             else:
#                 alg.do_command(GetOff, ifv_id, inf_id, myAgent)
#     else:
#         alg.do_command(Fail, ifv_id, myAgent)


def transport_method1(ifv_id, inf_id, tar_loc, myAgent):
    """2020-6-21 运输步兵"""
    while myAgent.get_bop(ifv_id)['move_path']:
        alg.do_command(Pass, ifv_id, myAgent)
    while myAgent.get_bop(inf_id)['get_off_remain_time'] <= 0:
        # begin = time.time()
        off_loc = infer_off_loc(ifv_id, tar_loc, myAgent)  # 根据步兵的目标点推理下车点
        # print(f'-- infer_off_loc time: {time.time() - begin:.3f}s off loc：{off_loc} obj_id: {ifv_id} tar loc: {tar_loc}')
        if myAgent.get_bop(ifv_id)['cur_hex'] != off_loc:
            move_path = gen_safe_route(myAgent.get_bop(ifv_id)['cur_hex'], off_loc,
                                       myAgent.get_bop(ifv_id)['type'], 0.5, myAgent)
            step_len, max_step, min_step = 3, 4, 2
            length = min(len(move_path) // step_len + min_step, max_step)
            next_path = move_path[0:length] if len(move_path) >= length else move_path
            while myAgent.get_bop(ifv_id)['cur_hex'] != next_path[-1]:
                if myAgent.get_bop(ifv_id)['stop'] == 0 and shoot_check(ifv_id, myAgent) and \
                        myAgent.get_bop(ifv_id)['sub_type'] != BopType.CruiseMissile:  # 具备行进间射击能力的算子，在遇到敌人时可以射击（巡飞弹除外）
                    alg.do_command(Fire, ifv_id, myAgent)
                elif occupy_check(myAgent.get_bop(ifv_id), myAgent.observation):
                    alg.do_command(Occupy, ifv_id, myAgent)
                else:
                    alg.do_command(MovePath, ifv_id, next_path, myAgent)
            if myAgent.get_city(next_path[-1]):  # 机动中可夺控M
                while occupy_check(myAgent.get_bop(ifv_id), myAgent.observation):
                    alg.do_command(Occupy, ifv_id, myAgent)
        else:
            while myAgent.get_bop(inf_id)['get_off_remain_time'] <= 0:
                alg.do_command(GetOff, ifv_id, inf_id, myAgent)
    alg.do_command(Pass, ifv_id, myAgent)


def fire_attack_method1(obj_id, tar_area, myAgent):
    """进攻型射击"""
    while enemies_in_area(tar_area, myAgent):  # 判断目标区域中是否有敌方单位
        if myAgent.get_bop(obj_id)['weapon_cool_time'] < 40:  # 为了“行进间射击”
            alg.do_task('direct_shooting', obj_id, [], myAgent)
        else:
            alg.do_command(Pass, obj_id, myAgent)
    # 如果目标区域中没有有敌方单位，fire_attack任务执行完毕


def fire_defend_method1(obj_id, myAgent):
    """防守型射击"""
    while True:
        if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
            alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
        else:
            alg.do_task('direct_shooting', obj_id, [], myAgent)
        # if myAgent.get_bop(obj_id)['weapon_cool_time'] < 40:  # 为了“行进间射击”
        #     alg.do_task('direct_shooting', obj_id, [], myAgent)
        # else:
        #     alg.do_command(Pass, obj_id, myAgent)


# def guard_tank_method1(obj_id, myAgent):
#     """警戒（坦克警戒）"""
#     if myAgent.get_bop(obj_id)['sub_type'] == BopType.Tank:
#         while not be_seen(obj_id, myAgent):  # 没有威胁
#             alg.do_command(Pass, obj_id, myAgent)
#         while be_seen(obj_id, myAgent):  # 被发现了，实施火力打击
#             alg.do_task('direct_shooting', obj_id, [], myAgent)
#     else:
#         alg.do_command(Fail, obj_id, myAgent)


def guard_common_method1(obj_id, myAgent):
    """警戒"""
    while True:
        if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
            alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
        else:
            alg.do_task('direct_shooting', obj_id, [], myAgent)


def guard2nd_common_method1(obj_id, shelter_flag, myAgent):
    """警戒 - 用于round 5"""
    if shelter_flag:
        while True:
            if (not be_seen(obj_id, myAgent)) and (not myAgent.get_bop(obj_id)['see_enemy_bop_ids']):
                alg.do_command(ChangeState, obj_id, MoveState.Shelter, myAgent)  # 进入掩蔽状态
            else:
                alg.do_task('direct_shooting', obj_id, [], myAgent)
            if myAgent.get_bop(obj_id)['sub_type'] == BopType.IFV:
                enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.Vehicle]
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
            elif myAgent.get_bop(obj_id)['sub_type'] == BopType.Helicopter:
                enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.LargeAircraft]
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
            elif myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
                artillery_threat = myAgent.agenda.rae_situation.artillery_threat
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if artillery_threat[cur_loc_ind] >= 3:  # 有3门炮同时到达本格，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
    else:
        while True:
            alg.do_task('direct_shooting', obj_id, [], myAgent)
            if myAgent.get_bop(obj_id)['sub_type'] == BopType.IFV:
                enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.Vehicle]
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
            elif myAgent.get_bop(obj_id)['sub_type'] == BopType.Helicopter:
                enemy_threat = myAgent.agenda.rae_situation.enemy_threat[ObservedType.LargeAircraft]
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if enemy_threat[cur_loc_ind] > 6:  # 威胁过大时，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)
            elif myAgent.get_bop(obj_id)['type'] == BopType.Infantry:
                artillery_threat = myAgent.agenda.rae_situation.artillery_threat
                cur_loc_ind = mapid_2_matind(myAgent.get_bop(obj_id)['cur_hex'], myAgent.get_map_size())
                if artillery_threat[cur_loc_ind] >= 1:  # 有1门炮到达本格，躲避
                    alg.do_task('hide2nd', obj_id, myAgent)


# def direct_shooting_common_method1(obj_id, tar_id, myAgent):
#     """直瞄射击"""
#     if not tar_id:
#         if shoot_check(obj_id, myAgent.agenda.rae_observation):  # 能射击就直接射击
#             alg.do_command(Fire, obj_id, myAgent)
#         elif move_n_shoot_ability(myAgent.agenda.get_bop(obj_id)):  # 只有坦克有行进间射击能力
#             if move_n_shoot_check(myAgent.agenda.get_bop(obj_id), myAgent.agenda.rae_observation):
#                 begin = time.time()
#                 path, fire_loc = infer_move_shoot_path(obj_id, myAgent)  # 推理出行进间射击的“射击位置”和“行进间射击路径”
#                 print(
#                     f'-- infer_move_shoot_path time: {time.time() - begin:.3f}s path：{path} fire loc: {fire_loc} obj id: {obj_id}')
#                 while 1 in myAgent.agenda.rae_observation['valid_actions'][obj_id] and \
#                         myAgent.agenda.get_bop(obj_id)['cur_hex'] in myAgent.map.get_neighbors(path[0]):
#                     alg.do_command(MovePath, obj_id, path, myAgent)
#                 while myAgent.agenda.get_bop(obj_id)['cur_hex'] != fire_loc:
#                     alg.do_command(Pass, obj_id, myAgent)
#                 while myAgent.agenda.get_bop(obj_id)['cur_hex'] == fire_loc:
#                     alg.do_command(Fire, obj_id, myAgent)
#             else:
#                 alg.do_command(Pass, obj_id, myAgent)
#         else:
#             alg.do_command(Fire, obj_id, myAgent)
#     else:
#         alg.do_command(Fail, obj_id, myAgent)
#
#
# def direct_shooting_target_method2(obj_id, tar_id, myAgent):
#     """直瞄射击"""
#     if tar_id:
#         if shoot_target_check(obj_id, tar_id, myAgent.agenda.rae_observation):  # 能射击就直接射击
#             alg.do_command(FireTarget, obj_id, tar_id, myAgent)
#         elif move_n_shoot_ability(myAgent.agenda.get_bop(obj_id)):  # 只有坦克有行进间射击能力
#             if move_n_shoot_check(myAgent.agenda.get_bop(obj_id), myAgent.agenda.rae_observation):
#                 begin = time.time()
#                 path, fire_loc = infer_move_shoot_path(obj_id, myAgent)  # 推理出行进间射击的“射击位置”和“行进间射击路径”
#                 print(
#                     f'-- infer_move_shoot_path time: {time.time() - begin:.3f}s path：{path} fire loc: {fire_loc} obj id: {obj_id}')
#                 while 1 in myAgent.agenda.rae_observation['valid_actions'][obj_id] and \
#                         myAgent.agenda.get_bop(obj_id)['cur_hex'] in myAgent.map.get_neighbors(path[0]):
#                     alg.do_command(MovePath, obj_id, path, myAgent)
#                 while myAgent.agenda.get_bop(obj_id)['cur_hex'] != fire_loc:
#                     alg.do_command(Pass, obj_id, myAgent)
#                 while myAgent.agenda.get_bop(obj_id)['cur_hex'] == fire_loc:
#                     alg.do_command(FireTarget, obj_id, tar_id, myAgent)
#             else:
#                 alg.do_command(Pass, obj_id, myAgent)
#         else:
#             alg.do_command(FireTarget, obj_id, tar_id, myAgent)
#     else:
#         alg.do_command(Fail, obj_id, myAgent)


# region 2020-6-12 根据infer_move_shoot_locs函数定制的直瞄射击分解方法
def direct_shooting_common_method1(obj_id, tar_id, myAgent):
    """直瞄射击"""
    if not tar_id:
        if shoot_check(obj_id, myAgent):  # 能射击就直接射击
            alg.do_command(Fire, obj_id, myAgent)
        elif move_n_shoot_ability(myAgent.get_bop(obj_id)):  # 只有坦克有行进间射击能力
            # begin = time.time()
            next_loc = infer_move_shoot_locs(obj_id, [], myAgent)  # 推理出行进间射击的“射击位置”和“行进间射击路径”
            # print(
            #     f'-- infer_move_shoot_locs time: {time.time() - begin:.3f}s  next_loc: {next_loc} obj id: {obj_id}')
            if not next_loc:  # 敌人已被消灭
                alg.do_command(Fail, obj_id, myAgent)
            elif next_loc == myAgent.get_bop(obj_id)['cur_hex']:  # 原地等待
                cur_step = myAgent.observation['time']['cur_step']
                wait_time = myAgent.get_bop(obj_id)['weapon_cool_time'] % 20.
                wait_time = 20. if abs(wait_time) < 1e-8 else wait_time
                while myAgent.observation['time']['cur_step'] < cur_step + wait_time:
                    alg.do_command(Fire, obj_id, myAgent)  # 有敌人就打，没有就Pass
            elif ActionType.Move in myAgent.observation['valid_actions'].get(obj_id, []) and \
                    myAgent.get_bop(obj_id)['cur_hex'] in myAgent.map.get_neighbors(next_loc):
                while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                    if shoot_check(obj_id, myAgent):
                        alg.do_command(Fire, obj_id, myAgent)
                    else:
                        alg.do_command(Move, obj_id, next_loc, myAgent)
                alg.do_command(Fire, obj_id, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
        else:
            alg.do_command(Fire, obj_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


def direct_shooting_target_method2(obj_id, tar_id, myAgent):
    """直瞄射击"""
    if tar_id:
        if shoot_target_check(obj_id, tar_id, myAgent.observation):  # 能射击就直接射击
            alg.do_command(FireTarget, obj_id, tar_id, myAgent)
        elif move_n_shoot_ability(myAgent.get_bop(obj_id)):  # 只有坦克有行进间射击能力
            # begin = time.time()
            next_loc = infer_move_shoot_locs(obj_id, tar_id, myAgent)  # 推理出行进间射击的“射击位置”和“行进间射击路径”
            # print(
            #     f'-- infer_move_shoot_locs time: {time.time() - begin:.3f}s  next_loc: {next_loc} obj id: {obj_id}')
            if not next_loc:  # 敌人已被消灭
                alg.do_command(Fail, obj_id, myAgent)
            elif next_loc == myAgent.get_bop(obj_id)['cur_hex']:  # 原地等待
                cur_step = myAgent.observation['time']['cur_step']
                wait_time = myAgent.get_bop(obj_id)['weapon_cool_time'] % 20.
                wait_time = 20. if abs(wait_time) < 1e-8 else wait_time
                while myAgent.observation['time']['cur_step'] < cur_step + wait_time:
                    alg.do_command(Fire, obj_id, myAgent)
            elif ActionType.Move in myAgent.observation['valid_actions'][obj_id] and \
                    myAgent.get_bop(obj_id)['cur_hex'] in myAgent.map.get_neighbors(next_loc):
                while myAgent.get_bop(obj_id)['cur_hex'] != next_loc:
                    if shoot_check(obj_id, myAgent):
                        alg.do_command(Fire, obj_id, myAgent)
                    else:
                        alg.do_command(Move, obj_id, next_loc, myAgent)
                alg.do_command(FireTarget, obj_id, tar_id, myAgent)
            else:
                alg.do_command(Pass, obj_id, myAgent)
        else:
            alg.do_command(FireTarget, obj_id, tar_id, myAgent)
    else:
        alg.do_command(Fail, obj_id, myAgent)


# endregion


# =========================
# ======= commands ========
# =========================

def Fail(obj_id, myAgent):
    return FAILURE


def Pass(obj_id, myAgent):
    return None


def Success(obj_id, myAgent):
    return SUCCESS


def GetOn(ifv_id, passenger_id, myAgent):
    """上车"""
    if get_on_check(ifv_id, passenger_id, myAgent.observation):
        res = {'obj_id': passenger_id,
               'type': ActionType.GetOn,
               'target_obj_id': ifv_id}
        return res
    else:
        return None


def GetOff(ifv_id, passenger_id, myAgent):
    """下车"""
    if get_off_check(ifv_id, passenger_id, myAgent.observation):
        res = {'obj_id': ifv_id,
               'type': 4,
               'target_obj_id': passenger_id}
        return res
    else:
        return None


def StopMove(obj_id, myAgent):
    """停止"""
    if obj_id in myAgent.observation['valid_actions'].keys():
        if ActionType.StopMove in myAgent.observation['valid_actions'][obj_id].keys():  # 可以执行停止动作
            res = {'obj_id': obj_id, 'type': ActionType.StopMove}
            return res
    else:
        return None


def Move(obj_id, loc, myAgent):
    """行进，这一版没有考虑行军"""
    if obj_id not in myAgent.observation['valid_actions'].keys():
        return None
    if ActionType.Move not in myAgent.observation['valid_actions'][obj_id].keys():  # 当前执行不了机动动作
        return None
    mod = get_mod(obj_id, myAgent)
    if loc:
        path = myAgent.map.gen_move_route(myAgent.get_bop(obj_id)['cur_hex'], loc, mod)  # 系统自带函数
        res = {'obj_id': obj_id, 'type': 1, 'move_path': path}
        return res
    else:
        return None


def MovePath(obj_id, path, myAgent):
    """依据所给路劲进行机动，后面考虑跟Move结合"""
    if obj_id not in myAgent.observation['valid_actions'].keys():
        return None
    if ActionType.Move not in myAgent.observation['valid_actions'][obj_id].keys():  # 当前执行不了机动动作
        return None
    if myAgent.get_bop(obj_id)['cur_hex'] not in myAgent.map.get_neighbors(path[0]):  # 算子的当前位置不在path的起始点
        return None
    if path:
        res = {'obj_id': obj_id, 'type': 1, 'move_path': path}
        return res
    else:
        return None


def Fire(obj_id, myAgent):
    """射击"""
    if not shoot_ability(obj_id, myAgent):  # 没有射击能力
        return FAILURE
    if not shoot_check(obj_id, myAgent):
        return None
    valid_fire_actions = []  # 记录所有有效的射击动作
    valid_actions_obj = myAgent.observation['valid_actions'][obj_id]
    if 2 in valid_actions_obj:
        valid_fire_actions += valid_actions_obj[2]  # 加入射击动作
    if 9 in valid_actions_obj:
        valid_fire_actions += valid_actions_obj[9]  # 加入引导射击动作
    # 找出伤害最大的射击动作进行输出
    best_fire_action = get_best_fire_action(obj_id, valid_fire_actions, myAgent)
    if 'guided_obj_id' not in best_fire_action.keys():  # 非引导射击
        res = {'obj_id': obj_id, 'type': 2, 'target_obj_id': best_fire_action['target_obj_id'],
               'weapon_id': best_fire_action['weapon_id']}
    else:  # 引导射击
        res = {'obj_id': obj_id, 'type': 9, 'target_obj_id': best_fire_action['target_obj_id'],
               'weapon_id': best_fire_action['weapon_id'], 'guided_obj_id': best_fire_action['guided_obj_id']}
    return res


def FireTarget(obj_id, tar_id, myAgent):
    """有目标的射击"""
    if not shoot_ability(obj_id, myAgent):  # 没有射击能力
        return FAILURE
    if not shoot_target_check(obj_id, tar_id, myAgent.observation):
        return None
    valid_fire_actions = []  # 记录所有有效的射击动作
    valid_actions_obj = myAgent.observation['valid_actions'][obj_id]
    if 2 in valid_actions_obj:
        for action in valid_actions_obj[2]:
            if action['target_obj_id'] == tar_id:
                valid_fire_actions.append(action)  # 加入射击动作
    if 9 in valid_actions_obj:
        for action in valid_actions_obj[9]:
            if action['target_obj_id'] == tar_id:
                valid_fire_actions.append(action)  # 加入引导射击动作
    # 找出伤害最大的射击动作进行输出
    best_fire_action = max(valid_fire_actions, key=lambda x: x['attack_level'])
    if 'guided_obj_id' not in best_fire_action.keys():  # 非引导射击
        res = {'obj_id': obj_id, 'type': 2, 'target_obj_id': tar_id, 'weapon_id': best_fire_action['weapon_id']}
    else:  # 引导射击
        res = {'obj_id': obj_id, 'type': 9, 'target_obj_id': tar_id, 'weapon_id': best_fire_action['weapon_id'],
               'guided_obj_id': best_fire_action['guided_obj_id']}
    return res


def ChangeState(obj_id, tar_state, myAgent):
    """改变状态"""
    if change_state_check(obj_id, tar_state, myAgent.observation):
        # print(f'obj_id: {obj_id} can change_state_check')
        res = {'obj_id': obj_id, 'type': 6, 'target_state': tar_state}
        return res
    else:
        # print(f'obj_id: {obj_id} not change_state_check')
        return None


def Occupy(obj_id, myAgent):
    """占领"""
    if occupy_check(myAgent.get_bop(obj_id), myAgent.observation):  # 可夺控
        res = {'obj_id': obj_id, 'type': 5}
        return res
    else:
        return None


def JMShoot(obj_id, tar_loc, myAgent):
    """间瞄射击"""
    if jm_shoot_check(myAgent.get_bop(obj_id), myAgent.observation):
        weapon_id = myAgent.get_bop(obj_id)['carry_weapon_ids'][0]
        res = {"obj_id": obj_id, "type": ActionType.JMPlan, "jm_pos": tar_loc, "weapon_id": weapon_id}
        return res
    else:
        return None


alg.declare_methods('output_firepower',
                    output_firepower_method1)

alg.declare_methods('defend_firepower',
                    defend_firepower_anti_control_methods1,
                    defend_firepower_common_method2)

alg.declare_methods('support_firepower',
                    support_firepower_guided_method1)

alg.declare_methods('scout',
                    scout_mothod1)

alg.declare_methods('hide',
                    hide_common_method1)

alg.declare_methods('hide2nd',
                    hide2nd_common_method1)

alg.declare_methods('control',
                    control_infantry_method1,
                    control_common_method2)

alg.declare_methods('try_control',
                    try_control_common_method1)

alg.declare_methods('load',
                    load_method1)

alg.declare_methods('unload',
                    unload_method1)

alg.declare_methods('deliver',
                    deliver_method1)

alg.declare_methods('deliver_safe',
                    deliver_safe_method1)

alg.declare_methods('cruise_missile_patrol',
                    cruise_missile_patrol_method1)

alg.declare_methods('cruise_missile',
                    cruise_missile_method1)

alg.declare_methods('cruise_missile_2nd',
                    cruise_missile_2nd_method1)

alg.declare_methods('ambush',
                    ambush_tank_method1,
                    ambush_common_method2)

alg.declare_methods('ambush2nd',
                    ambush2nd_infantry_method1,
                    ambush2nd_common_method2)

alg.declare_methods('ambush3rd',
                    ambush3rd_common_method1)

alg.declare_methods('ambush4th',
                    ambush4th_tank_method1,
                    ambush4th_common_method2)

alg.declare_methods('air_defense',
                    air_defense_infantry_method1)

alg.declare_methods('hunt',
                    hunt_method1)

alg.declare_methods('targeted_kill',
                    targeted_kill_cm_method1,
                    targeted_kill_common_method2)

alg.declare_methods('fire_propulsion',
                    fire_propulsion_aircraft_method1,
                    fire_propulsion_common_method2)

alg.declare_methods('assult',
                    assult_common_method1)

alg.declare_methods('search_clean',
                    search_clean_tank_method1)

alg.declare_methods('guide_fire',
                    guide_fire_method1)

alg.declare_methods('jm_salvo',
                    jm_salvo_method1)

alg.declare_methods('direct_artilleries',
                    direct_artilleries_method1)

alg.declare_methods('infantry_tank_coordination',
                    infantry_tank_coordination_method1)

alg.declare_methods('drone_scout',
                    drone_scout_method1)

alg.declare_methods('maneuver',
                    maneuver_aircraft_method1,
                    maneuver_path_infantry_method2,
                    maneuver_infantry_method3,
                    maneuver_path_common_method4,
                    maneuver_common_method5)

alg.declare_methods('rapid_march',
                    rapid_march_aircraft_method1,
                    rapid_march_infantry_method2,
                    rapid_march_common_method3)

# alg.declare_methods('march',
#     march_rapid_method1,
#     march_organized_method2)

alg.declare_methods('transport',
                    transport_method1)

alg.declare_methods('fire_attack',
                    fire_attack_method1)

alg.declare_methods('fire_defend',
                    fire_defend_method1)

alg.declare_methods('guard',
                    guard_common_method1)

alg.declare_methods('guard2nd',
                    guard2nd_common_method1)

alg.declare_methods('direct_shooting',
                    direct_shooting_common_method1,
                    direct_shooting_target_method2)

alg.declare_commands([
    Fail,
    Pass,
    Success,
    GetOn,
    GetOff,
    StopMove,
    Move,
    MovePath,
    Fire,
    FireTarget,
    ChangeState,
    Occupy,
    JMShoot])
